package org.yacon;

import java.util.Collections;
import java.util.Set;
import java.util.Map;

import static org.yacon.ConsoleEngineConstants.HELP;

/**
 * Performs validation of User specified command according to XML Commands configuration
 *
 * @author Evgeny Vetrov
 * @see CommandParser
 * @see ConsoleConfiguration
 */
class CommandValidator
{
    /**
     * Performs validation of User specified command according to XML Commands configuration
     *
     * @param cmdParser     parsed representation of User specified command
     * @param configuration parsed representation of parsed XML Commands configuration
     * @param context       program object if validation is executed in context of this program
     * @throws HelpException In case of validation error. Validation error can occur if wrong command, parameter,
     *                       or parameter value is specified in User defined command.
     */
    static void validate(CommandParser cmdParser, ConsoleConfiguration configuration, Program context)
            throws HelpException
    {
        ConsoleCommand command = context == null ? configuration.getCommand(cmdParser.getCommandName()) :
                context.getCommandsMap().get(cmdParser.getCommandName());
        Program program = context != null ? null : configuration.getProgram(cmdParser.getCommandName());
        if (command == null && program == null)
            throw new HelpException("Specified command '" + cmdParser.getCommandName() + "' doesn't exists. Type \""
                    + HELP + "\" to see the list of available commands");
        Set<CommandParameter> params;
        if (program == null)
            params = command.getParams();
        else
            params = program.getInitCommand() == null ? Collections.<CommandParameter>emptySet()
                    : program.getInitCommand().getParams();
        validateParams(params, cmdParser.getCommandParametersValues());
    }

    @SuppressWarnings("SuspiciousMethodCalls")
    private static void validateParams(Set<CommandParameter> cmdParams, Map<String, Object> paramsValues)
            throws HelpException
    {
        for (CommandParameter param : cmdParams) {
            Object value = paramsValues.get(param.getName());
            if ((value == null || "".equals(value)) && param.isRequired()) {
                throw new HelpException("Parameter \"" + param.getName() + "\" is required. " +
                        "Type \"help <command name>\" to see the the full description of command and it's parameters");
            }
            Map<String, Set<CommandParameter>> innerParams = param.getParams();
            if (!innerParams.isEmpty()) {
                if (!(innerParams.containsKey(value) || innerParams.containsKey("")))
                    throw new HelpException("Value of parameter \"" + param.getName() +
                            "\" must be one of the following: " + innerParams.keySet());
                validateParams(param.getParams().get(value), paramsValues);
            }
        }
    }
}
